package drds.server.route.parser.core.impl;

import java.sql.SQLNonTransientException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import drds.server.cache.LayeredCache;
import drds.server.config.model.Schema;
import drds.server.execute_engine.data_handling.RangeValue;
import drds.server.route.Route;
import drds.server.route.parser.core.ParserResult;
import drds.server.route.parser.core.ShardInfoVisitor;
import drds.server.route.parser.core.SqlParser;
import drds.server.route.parser.core.TableColumnValueSetMap;
import drds.server.sqlparser.sqlobject.statement.Statement;
import drds.server.sqlparser.table.ShardKeyValue;

/**
 * <pre>
 * insert 语句 全局表  单表  ER  
 * update 语句 and or in 不支持存在语句 需要带切分键或者主键
 * delete 语句 and or in 不支持存在语句 需要带切分键或者主键
 * select 语句 and or in union join 持存在语句  需要带切分键或者主键
 * in 语句可以改写会and语句
 * 上面四种语句,系统会生成一种带路由组数据库节点的标记信息。
 * 
 * 
 * 
 * select 语句首先在where条件开始的时候提出切分条件，然后才是正常的SQL语句
 * </pre>
 * 
 * @author 曹正辉<330937205@qq.com>
 */
public class DefaultParser implements SqlParser {
	protected static final Logger LOGGER = LoggerFactory.getLogger(DefaultParser.class);
	/**
	 * 解析得到的结果
	 */
	protected ParserResult parserResult;

	private Map<String, String> tableAliasMap = new HashMap<String, String>();

	private List<ShardKeyValue> shardKeyValueList = new ArrayList<ShardKeyValue>();

	public Map<String, String> getTableAliasMap() {
		return tableAliasMap;
	}

	public List<ShardKeyValue> getShardKeyValueList() {
		return shardKeyValueList;
	}

	/**
	 * 使用SchemaStatVisitor解析,得到tables、tableAliasMap、conditions等
	 */
	public void parseSql(//
			Route route, //
			String sql,//
			Schema schema,//
			Statement statement,//
			ShardInfoVisitor visitor,//
			LayeredCache cache) throws SQLNonTransientException {
		parserResult = new ParserResult();
		parserResult.setSql(sql);
		visitorParse(route, statement, visitor);
		statementParse(route, schema, statement);

		// 改写sql：如insert语句主键自增长的可以
		changeSql(schema, route, statement, cache);
	}

	/**
	 * 子类可覆盖（如果visitorParse解析得不到表名、字段等信息的，就通过覆盖该方法来解析）
	 * 子类覆盖该方法一般是将SQLStatement转型后再解析（如转型为MySqlInsertStatement）
	 */
	public void statementParse(Route route, Schema schema, Statement statement) throws SQLNonTransientException {

	}

	/**
	 * 改写sql：如insert是
	 */
	@Override
	public void changeSql(Schema schema, Route route, Statement statement, LayeredCache cachePool) throws SQLNonTransientException {

	}

	/**
	 * 子类可覆盖（如果该方法解析得不到表名、字段等信息的，就覆盖该方法，覆盖成空方法，然后通过statementPparse去解析）
	 * 通过visitor解析：有些类型的Statement通过visitor解析得不到表名、
	 * 
	 */
	@Override
	public void visitorParse(Route route, Statement statement, ShardInfoVisitor shardInfoVisitor) {
		// 对statement进行遍历获取切分条件
		statement.accept(shardInfoVisitor);
		/**
		 * 带切分键拆分
		 */
		List<List<ShardKeyValue>> shardKeyValueListList = new ArrayList<List<ShardKeyValue>>();
		if (shardInfoVisitor.hasOr()) {// 包含or语句
			// 根据or拆分
			shardKeyValueListList = shardInfoVisitor.split();
		} else {
			// 不包含OR语句
			shardKeyValueListList.add(shardInfoVisitor.getShardKeyValueList());
		}

		if (shardInfoVisitor.getColumnAliasMap() != null) {
			for (Map.Entry<String, String> entry : shardInfoVisitor.getColumnAliasMap().entrySet()) {
				String alias = entry.getKey();
				String tableName = entry.getValue();

				if (alias != null) {
					if (alias.equals(tableName)) {
						parserResult.addTableName(alias);
					}
					tableAliasMap.put(alias, tableName);
				}

			}
			shardInfoVisitor.getColumnAliasMap().putAll(tableAliasMap);

			Map<String, String> columnAliasMap = new HashMap<String, String>();
			parserResult.setColumnAliasMap(columnAliasMap);
			parserResult.setTableAliasMap(tableAliasMap);
		}
		/**
		 * 设置多组条件的切分信息,一个list元素就是一组切分信息
		 */
		parserResult.setTableColumnValueSetMapList(this.buildTableColumnValueSetMapList(shardInfoVisitor, shardKeyValueListList));
	}

	/**
	 * 只针对partition_eq partition_between partition_in三组操作符进行处理。
	 */
	private List<TableColumnValueSetMap> buildTableColumnValueSetMapList(//
			ShardInfoVisitor visitor, //
			List<List<ShardKeyValue>> shardKeyValueListList) {//
		List<TableColumnValueSetMap> tableColumnValueSetMapList = new ArrayList<TableColumnValueSetMap>();
		int size = shardKeyValueListList.size();
		for (int i = 0; i < size; i++) {
			TableColumnValueSetMap tableColumnValueSetMap = new TableColumnValueSetMap();
			for (ShardKeyValue shardKeyValue : shardKeyValueListList.get(i)) {
				List<Object> valueList = shardKeyValue.getValueList();
				if (valueList.size() == 0) {
					throw new IllegalArgumentException("valueList.size() == 0");
				}

				String tableName = shardKeyValue.getColumn().getTableName();
				String columnName = shardKeyValue.getColumn().getColumnName();

				String operator = shardKeyValue.getOperator();
				if (operator.equals("pk_between")) {
					RangeValue rangeValue = new RangeValue(valueList.get(0), valueList.get(1), RangeValue.EE);
					tableColumnValueSetMap.addValue(tableName, columnName, rangeValue);
				} else if (operator.equals("pk_eq") || operator.equals("pk_in")) {
					tableColumnValueSetMap.addValue(tableName, columnName, valueList.toArray());
				} else {
					throw new RuntimeException("现在还不支持其他的分组语法");
				}

			}
			tableColumnValueSetMapList.add(tableColumnValueSetMap);
		}
		return tableColumnValueSetMapList;
	}

	public ParserResult getParserResult() {
		return parserResult;
	}

}
